/**
 * 
 */
package com.gragra.sampling.binary;
import com.gragra.sampling.PopulationProbabilityAssigner;
import com.gragra.sampling.ThreadedUniformAccess;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
/**
 * @author Christoph Teichmann
 * 15.09.2013
 */
public class BinaryPop extends BinaryChart
{
	private void testWithinSize()
	{
		if(!(this.getLength()<=Short.MAX_VALUE))
		{throw new IllegalArgumentException("Maximum sentence length for BinaryPop class is: "+Short.toString(Short.MAX_VALUE));}
	}
	/* (non-Javadoc)
	 * @see com.gragra.sampling.binary.BinaryStructure#initialize(com.gragra.sampling.PopulationProbabilityAssigner, com.gragra.sampling.ThreadedUniformAccess)
	 */
	@Override
	public void initialize(PopulationProbabilityAssigner pa,
			ThreadedUniformAccess tua)
	{
		super.initialize(pa, tua);
		for(int thread=0;thread<this.getNumberOfThreads();++thread)
		{this.changeCounts(1.0, thread);}
	}
	/**
	 * 
	 */
	private final double smoothingFactor;
	/**
	 * 
	 */
	private final AVLTripleCounter counts = new AVLTripleCounter();
	/**
	 * 
	 */
	private final PairCounter pc = new PairCounter();
	/**
	 * @param wth
	 * @param threads
	 * @param cs
	 */
	public BinaryPop(WordAndTagHolder wth, int threads, ConvertSample cs, double smooth, boolean sampleHead)
	{
		super(wth, threads, cs,sampleHead);
		this.smoothingFactor = smooth;
		testWithinSize();
	}
	/* (non-Javadoc)
	 * @see com.gragra.sampling.binary.BinarySplitGibbs#addAfter(com.gragra.sampling.binary.BinaryAssigner, int)
	 */
	@Override
	public void addAfter(PopulationProbabilityAssigner ba, int thread)
	{
		this.changeCounts(1.0,thread);
		super.addAfter(ba, thread);
	}
	/* (non-Javadoc)
	 * @see com.gragra.sampling.binary.BinarySplitGibbs#removeBefore(com.gragra.sampling.binary.BinaryAssigner, int)
	 */
	@Override
	public void removeBefore(PopulationProbabilityAssigner ba, int thread)
	{
		this.changeCounts(-1.0,thread);
		super.removeBefore(ba, thread);
	}
	/**
	 * 
	 * @param d
	 * @param thread
	 */
	protected void changeCounts(double by, int thread)
	{
		if(this.getLength() == 1)
		{return;}
		for(int node= this.getLength();node<=this.getRootPosition();++node)
		{
			int from = this.getFrom(node, thread);
			int to = this.getTo(node, thread);
			int middle = this.getMiddle(node, thread);
			this.counts.changeVal((short) from,(short) to,(short) middle, by);
			this.pc.add(from,to,by);
			if(this.getHeadLeft(middle, thread))
			{this.leftCounts.changeVal((short) from,(short) to,(short) middle, by);}
		}
	}
	@Override
	protected double getLogChoiceProb(int from, int to, int middle, int thread)
	{return Math.log(this.counts.getAmount((short) from,(short) to,(short) middle)+this.smoothingFactor);}
	@Override
	protected double getLogNormalizer(int from, int to, int thread)
	{return Math.log(this.pc.get(from, to)+((to-from-1)*this.smoothingFactor));}
	@Override
	protected void createChart(double annealing, int thread, PopulationProbabilityAssigner ba)
	{}
	@Override
	protected void clearChart()
	{}
	@Override
	protected double getLogNormLeftProb(int from, int to, int middle,
			int thread)
	{return Math.log(this.counts.getAmount((short) from,(short) to,(short) middle)+2*this.smoothingFactor);}
	@Override
	protected double getLogLeftProb(int from, int to, int middle, int thread)
	{return Math.log(this.leftCounts.getAmount((short) from,(short) to,(short) middle)+this.smoothingFactor);}
	/**
	 * 
	 */
	private final AVLTripleCounter leftCounts = new AVLTripleCounter();
}